package project.base.common.database

import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.EnableAspectJAutoProxy
import org.springframework.core.annotation.Order
import project.base.common.annotation.DataSource
import java.util.*

/**
 *
 * @author: 三味
 * @update: 2022/3/2 20:25
 */
@Aspect
@Configuration
@Order(-1)
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
open class DataSourceAspect {
    @Pointcut("@within(project.base.common.annotation.DataSource) || @annotation(project.base.common.annotation.DataSource)")
    fun dataSourcePointCut() {
    }

    @Around("dataSourcePointCut()")
    @Throws(Throwable::class)
    fun around(joinPoint: ProceedingJoinPoint): Any? {
        val dsKey: String = getDSAnnotation(joinPoint).value
        DbContextHolder.setDataSource(dsKey)
        return try {
            joinPoint.proceed()
        } finally {
            DbContextHolder.clearDataSource()
        }
    }

    /**
     * 根据类或方法获取数据源注解
     */
    private fun getDSAnnotation(joinPoint: ProceedingJoinPoint): DataSource {
        val targetClass: Class<*> = joinPoint.target.javaClass
        val dsAnnotation: DataSource = targetClass.getAnnotation(DataSource::class.java)
        // 先判断类的注解，再判断方法注解
        return if (Objects.nonNull(dsAnnotation)) {
            dsAnnotation
        } else {
            val methodSignature = joinPoint.signature as MethodSignature
            methodSignature.method.getAnnotation(DataSource::class.java)
        }
    }
}
